﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using System.Runtime.Serialization;
using System.Xml;
using COFE.Core;
using System.Xml.Linq;

namespace COFE.Web.Utils
{  
    public class COFEWSEntitiesContractBehaviorAttribute : Attribute, IContractBehavior
    {

        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {            
        }

        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            this.ReplaceSerializerOperationBehavior(contractDescription);
        }

        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
        {
            this.ReplaceSerializerOperationBehavior(contractDescription);
        }

        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        {
            
        }

        //http://www.codeproject.com/Articles/434665/WCF-Serialization-A-Case-Study
        private void ReplaceSerializerOperationBehavior(ContractDescription contract)
        {
            foreach (OperationDescription od in contract.Operations)
            {
                for (int i = 0; i < od.Behaviors.Count; i++)
                {
                    DataContractSerializerOperationBehavior dcsob = od.Behaviors[i] as DataContractSerializerOperationBehavior;
                    if (dcsob != null)
                    {
                        od.Behaviors[i] = new COFEWSOperationBehavior(od);
                    }
                }
            }
        }
       
    }
   
    internal class COFEWSOperationBehavior : DataContractSerializerOperationBehavior
    {
        public COFEWSOperationBehavior(OperationDescription operation) : base(operation) { }

        public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
        {
            return new COFEObjSerializer();
        }

        public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
        {
            return new COFEObjSerializer();
        }
    }

    internal class COFEObjSerializer : XmlObjectSerializer
    {

        public override bool IsStartObject(XmlDictionaryReader reader)
        {
            return true;
        }

        public override object ReadObject(System.IO.Stream stream)
        {
            return XmlStreamUtils.ObjectFromXmlStream(COFEShared.CurrentUserProfile, stream);
        }

        public override void WriteObject(System.IO.Stream stream, object graph)
        {
            if (!(graph is ISupportXml))
                throw new NotSupportedException();

            using (var sw = new System.IO.StreamWriter(stream))
                sw.Write((graph as ISupportXml).ToXmlStream());
        }



        public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
        {
            XElement el = XElement.Load(reader);
            return XmlStreamUtils.ObjectFromXmlElement(COFEShared.CurrentUserProfile, el);
        }

        public override void WriteEndObject(XmlDictionaryWriter writer)
        {
            
        }

        public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
        {
            if (!(graph is ISupportXml))
                throw new NotSupportedException();

            var graphXml = (graph as ISupportXml).ToXml();
            graphXml.WriteTo(writer);
        }

        public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
        {
            
        }
    }
}
